<?php
declare(strict_types=1);
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author X.Mo<root@imoi.cn>
 * @Link   https://gitee.com/xmo/MineAdmin
 */

namespace Plugin\Alarm\Service;

use App\Service\IService;
use Common\Common;
use Hyperf\Carbon\Carbon;
use Hyperf\Collection\Arr;
use Hyperf\Event\EventDispatcher;
use Plugin\Alarm\Event\AlarmEvent;
use Plugin\Alarm\Repository\RdAlarmBroadcastRecordRepository;
use Plugin\Alarm\Repository\RdAlarmTypeRepository;
use Plugin\Alarm\Repository\RdAlarmWarnRecordRepository;
use Plugin\Alarm\Repository\RdAlarmWorkRepository;
use Plugin\Device\Repository\RdDeviceBroadcastRepository;
use Plugin\Device\Repository\RdDeviceBroadcastServerRepository;
use Plugin\Device\Repository\RdDeviceRodRepository;
use Plugin\Device\Repository\RdDeviceSerialRepository;
use Plugin\Device\Service\IpBroadcastService;
use Plugin\File\Service\VoiceService;
use Plugin\Organization\Repository\RdOrganizeUserStandRepository;

/**
 * 报警记录服务类
 */
final class RdAlarmWarnRecordService extends IService
{
    public function __construct(
        protected readonly RdAlarmWarnRecordRepository       $repository,
        protected readonly RdDeviceSerialRepository          $deviceSerialRepository,
        protected readonly RdDeviceRodRepository             $deviceRodRepository,
        protected readonly RdDeviceBroadcastRepository       $broadcastRepository,
        protected readonly IpBroadcastService                $ipBroadcastService,
        protected readonly RdDeviceBroadcastServerRepository $serverRepository,
        protected readonly RdAlarmTypeRepository             $typeRepository,
        protected readonly VoiceService                      $voiceService,
        protected readonly RdAlarmBroadcastRecordRepository  $broadcastRecordRepository,
        protected readonly EventDispatcher                   $eventDispatcher,
        protected readonly RdOrganizeUserStandRepository     $userStandRepository,
        protected readonly RdAlarmWorkService                $workService,
    )
    {
    }

    public function warn($msg, int $time)
    {
//        对应摄像头
        $camera = $this->deviceSerialRepository->findByFilter([
            'device_serial' => Arr::get($msg, 'device_serial', ''),
            'channel_no' => Arr::get($msg, 'channel_no', -1),
        ]);
        if (!$camera) {
            return false;
        }
        $rod = $this->deviceRodRepository->findById($camera->rod_id);
        if (!$rod) {
            return false;
        }
        $eventType = $this->typeRepository->findById($msg['type']);
//        广播
        $now = Carbon::now();
        if ($now->hour >= 8 && $now->hour < 20 && $eventType && $eventType->voice_id > 0) {
//        组合音频
            $cameraVoiceId = $camera->voice_id ?? 0;
            $complyVoiceId = $camera->comply_id ?? 0;
            $eventVoiceId = $eventType->voice_id;
            try {
                $voice = $this->ipBroadcastService->mergeVoice([$cameraVoiceId, $eventVoiceId, $complyVoiceId]);
            } catch (\Exception $e) {
                $voice['file'] = '';
            }
            $file = env('APP_HOST') . '/' . $voice['file'];
//        广播
            $query = $this->broadcastRepository->getQuery()
                ->where('rod_id', $rod->id);
            $broadcasts = $query->get();
            $servers = $this->serverRepository
                ->list(['id' => $query->pluck('server_id')->toArray()])
                ->keyBy('id')
                ->toArray();
            $speech = [];
            foreach ($broadcasts as $broadcast) {
                $speech[$broadcast->server_id][] = $broadcast->device_id;
            }
            $ids = [];
            $start = time();
//        发送广播
            foreach ($speech as $serverId => $deviceIds) {
                $this->ipBroadcastService->speech([
                    'id' => $serverId,
                    'url' => $servers[$serverId]['link'],
                    'ids' => $deviceIds,
                    'username' => $servers[$serverId]['username'],
                    'password' => Common::aesDecrypt($servers[$serverId]['password'], env('AES_KEY')),
                    'file' => $file,
                ]);
                $ids = array_merge($ids, $deviceIds);
            }
//        广播记录
            $broadcastRecord = $this->broadcastRecordRepository->create([
                'file_id' => $voice['id'],
                'device' => $ids,
                'type' => 1,
                'start_time' => $start,
                'second' => $this->voiceService::getAudioDuration($voice['file'])
            ]);

        }
        $this->eventDispatcher->dispatch(new AlarmEvent($msg['id'], $rod->stand_id, $eventType->id ?? 0));
        $record = $this->repository->create([
            'type' => $eventType->id ?? 0,
            'msg_id' => $msg['id'],
            'broadcast_id' => isset($broadcastRecord)? $broadcastRecord->id : 0,
            'stand_id' => $rod->stand_id,
            'rod_id' => $rod->id,
            'warning_time' => $time,
            'device_id' => $camera->id,
            'risk_level' => $eventType->risk_level ?? 0,
            'title' => Arr::get($msg, 'title') ?? $eventType->risk_title ?? '' ,
            'content' => Arr::get($msg, 'content') ?? $eventType->risk_content ?? '',
            'msg_type' => $msg['type'],
        ]);
        //创建工单
        if ($eventType->level == 1) {
            $work = $this->workService->workCreate([
                'title' => Arr::get($msg, 'title') ?? $eventType->risk_title ?? 'AI预警',
                'content' => Arr::get($msg, 'content') ?? $eventType->risk_content ?? '',
                'stand_id' => $rod->stand_id,
                'type' => 1,
                'expire_at' => $now->addSeconds(intval($eventType->expire_time ?? 0))->timestamp,
                'priority' => $eventType->risk_level ?? 1,
                'related_type' => 1,
                'related_id' => $record->id,
                'created_by' => 0,
            ]);
            if ($work) {
                $record->update([
                    'work_id' => $work->id,
                ]);
            }
        }
        return $record;
    }

    public function detail(int $id)
    {
        return $this->repository->detail($id);
    }

}